[JAWS] AWSMを使って認証・認可APIを作る
モバイルアプリサービス部の五十嵐です。
10/30に弊社で行われた『モバイルバックエンド勉強会 In 秋葉原』で、JAWSについてトークしました。その中でデモとして行った、認証・認可APIの作り方をご紹介します。
[レポート]モバイルバックエンド勉強会 In 秋葉原 #cmdevio | Developers.IO
スライド
デモ
スライドの中のデモで行ったawsm-usersをダウンロードしてデプロイするまでの手順を以下に記載します。
できるもの
awsm-usersを使うことで、認証・認可に必要な最低限のAPIが作成されます。
- [POST] /users/create
- [POST] /users/authenticate
- [GET] /users/list *認可必要
事前準備
Node.js / npm のインストール
JAWSはJavaScriptで書かれており、npmで配布されています。手元の環境にNode.jsとnpmがない場合は、インストールしてください。
参考: nodebrewでNode.jsをバージョン管理 - Node.jsとRubyの環境構築(2) - Qiita
JAWS のインスト−ル
JAWSをnpmでインストールします。
$ npm install jaws-framework -g
プロジェクトの作成
JAWSのプロジェクトを作成します。コマンドなどの詳細はサーバレスアプリケーションフレームワーク JAWS を使ってみる | Developers.IOを参考にしてください。
$ jaws project create ____ _____ __ __ _________ | | / _ \/ \ / \/ _____/ | |/ /_\ \ \/\/ /\_____ \ /\__| / | \ / / \ \________\____|__ /\__/\__/ /_________/ v1 (BETA) *** The Server-Less Framework *** JAWS: Enter a project name: (jaws-E1XgDRPWx) demo JAWS: Enter a project domain (You can change this at any time: (myapp.com) JAWS: Enter an email to use for AWS alarms: (you@yourapp.com) JAWS: Enter a stage for this project: (dev) JAWS: Select a region for your project: us-east-1 us-west-2 eu-west-1 > ap-northeast-1 JAWS: Select an AWS profile for your project: > default JAWS: Creating CloudFormation Stack for your new project (~5 mins)... JAWS: Preparing your runtime and installing jaws-core module... sample-app@0.0.1 /Users/igarashi.ryosuke/temp/jaws/sample-app └─┬ jaws-core-js@0.0.2 └── dotenv@1.2.0 npm WARN EPACKAGEJSON sample-app@0.0.1 No license field. JAWS: Your project "sample-app" has been successfully created in the current directory. $ cd demo
AWSMのダウンロードと組み込み
npm install
コマンドでawsm-usersをダウンロードし、jaws postinstall
でダウンロードしたnpmをプロジェクトのaws_modulesに追加します。
$ npm install --save awsm-users $ jaws postinstall awsm-users npm
環境変数の設定
プロジェクトの環境変数を確認すると、設定されていない環境変数が3つあることがわかります。 Lambda自体には環境変数はありませんが、JAWSが環境変数を使えるようにしています。
$ jaws env list dev ap-northeast-1 JAWS: Getting ENV file from S3 bucket: jaws.dev.apnortheast1.myapp-vkdqvcpw.com in ap-northeast-1 JAWS: ENV vars for stage dev: JAWS: ------------------------------ JAWS: ap-northeast-1 JAWS: ------------------------------ JAWS_STAGE=dev JAWS_DATA_MODEL_STAGE=dev JAWS: awsm.json:lambda.envVars and regions where they are used (red means NOT defined in region): JAWS: ------------------------------ JAWS: USERS_TABLE JAWS: ------------------------------ JAWS: aws mods using: awsm-users/create/awsm.json,awsm-users/authenticate/awsm.json,awsm-users/list/awsm.json JAWS: regions: ap-northeast-1 JAWS: ------------------------------ JAWS: JWT_SECRET JAWS: ------------------------------ JAWS: aws mods using: awsm-users/authenticate/awsm.json JAWS: regions: ap-northeast-1 JAWS: ------------------------------ JAWS: JWT_ISSUER JAWS: ------------------------------ JAWS: aws mods using: awsm-users/authenticate/awsm.json JAWS: regions: ap-northeast-1
awsm-usersに必要な環境変数を設定をします。
$ jaws env set dev ap-northeast-1 USERS_TABLE jaws-users $ jaws env set dev ap-northeast-1 JWT_SECRET secret $ jaws env set dev ap-northeast-1 JWT_ISSUER issuer
再び環境変数を確認すると、設定されたことがわかります。
$ jaws env list dev ap-northeast-1 JAWS: Getting ENV file from S3 bucket: jaws.dev.apnortheast1.myapp-vkdqvcpw.com in ap-northeast-1 JAWS: ENV vars for stage dev: JAWS: ------------------------------ JAWS: ap-northeast-1 JAWS: ------------------------------ JAWS_STAGE=dev JAWS_DATA_MODEL_STAGE=dev USERS_TABLE=jaws-users JWT_SECRET=secret JWT_ISSUER=issuer JAWS: awsm.json:lambda.envVars and regions where they are used (red means NOT defined in region): JAWS: ------------------------------ JAWS: USERS_TABLE JAWS: ------------------------------ JAWS: aws mods using: awsm-users/list/awsm.json,awsm-users/create/awsm.json,awsm-users/authenticate/awsm.json JAWS: regions: ap-northeast-1 JAWS: ------------------------------ JAWS: JWT_SECRET JAWS: ------------------------------ JAWS: aws mods using: awsm-users/authenticate/awsm.json JAWS: regions: ap-northeast-1 JAWS: ------------------------------ JAWS: JWT_ISSUER JAWS: ------------------------------ JAWS: aws mods using: awsm-users/authenticate/awsm.json JAWS: regions: ap-northeast-1
デプロイ
デプロイは2つあります。1つはLambda、API Gateway以外のリソース(ここではDynamoDBなど)のデプロイで、jaws deploy resources
コマンドで実行できます。
$ jaws deploy resources JAWS: Resources Deployer "dev": Deploying resources to region "ap-northeast-1"... JAWS: Resources Deployer "dev - ap-northeast-1": Performing Cloudformation stack update. This could take a while depending on how many resources you are updating... JAWS: Resources Deployer "dev - ap-northeast-1": Cloudformation stack update completed successfully!
もう一つはLambdaとAPI Gatewayのデプロイで、jaws dash
コマンドで実行できます。
$ jaws dash JAWS: Dashboard for project "sample-app" ------------------------------------------- Project Summary ------------------------------------------- Stages: dev ap-northeast-1 Lambdas: 3 Endpoints: 3 ------------------------------------------- Select Resources To Deploy ------------------------------------------- awsm-users/create L) lAwsmUsersCreate E) /users/create - POST awsm-users/authenticate L) lAwsmUsersAuthenticate E) /users/authenticate - POST awsm-users/list L) lAwsmUsersList E) /users/list - GET - - - - - > Deploy Selected --> JAWS: ------------------------------------------- JAWS: Dashboard: Deploying Lambdas... JAWS: ------------------------------------------- JAWS: Lambda Deployer: Packaging "lAwsmUsersList"... JAWS: Lambda Deployer: Saving in dist dir /var/folders/zz/lwbnbx41153d7k9cwy_y3f4r0000gp/T/lAwsmUsersList@1445934268684 JAWS: Getting ENV file from S3 bucket: jaws.dev.apnortheast1.myapp-vkdqvcpw.com in ap-northeast-1 JAWS: Lambda Deployer: Bundled file written to /var/folders/zz/lwbnbx41153d7k9cwy_y3f4r0000gp/T/lAwsmUsersList@1445934268684/bundled.js JAWS: Lambda Deployer: Minified file written to /var/folders/zz/lwbnbx41153d7k9cwy_y3f4r0000gp/T/lAwsmUsersList@1445934268684/minified.js JAWS: Lambda Deployer: Compressed lambda written to /var/folders/zz/lwbnbx41153d7k9cwy_y3f4r0000gp/T/lAwsmUsersList@1445934268684/package.zip JAWS: Lambda Deployer: Uploading lAwsmUsersList to jaws.dev.apnortheast1.myapp-vkdqvcpw.com JAWS: Lambda Deployer: Packaging "lAwsmUsersAuthenticate"... JAWS: Lambda Deployer: Saving in dist dir /var/folders/zz/lwbnbx41153d7k9cwy_y3f4r0000gp/T/lAwsmUsersAuthenticate@1445934276325 JAWS: Getting ENV file from S3 bucket: jaws.dev.apnortheast1.myapp-vkdqvcpw.com in ap-northeast-1 JAWS: Lambda Deployer: Bundled file written to /var/folders/zz/lwbnbx41153d7k9cwy_y3f4r0000gp/T/lAwsmUsersAuthenticate@1445934276325/bundled.js JAWS: Lambda Deployer: Minified file written to /var/folders/zz/lwbnbx41153d7k9cwy_y3f4r0000gp/T/lAwsmUsersAuthenticate@1445934276325/minified.js JAWS: Lambda Deployer: Compressed lambda written to /var/folders/zz/lwbnbx41153d7k9cwy_y3f4r0000gp/T/lAwsmUsersAuthenticate@1445934276325/package.zip JAWS: Lambda Deployer: Uploading lAwsmUsersAuthenticate to jaws.dev.apnortheast1.myapp-vkdqvcpw.com JAWS: Lambda Deployer: Packaging "lAwsmUsersCreate"... JAWS: Lambda Deployer: Saving in dist dir /var/folders/zz/lwbnbx41153d7k9cwy_y3f4r0000gp/T/lAwsmUsersCreate@1445934279765 JAWS: Getting ENV file from S3 bucket: jaws.dev.apnortheast1.myapp-vkdqvcpw.com in ap-northeast-1 JAWS: Lambda Deployer: Bundled file written to /var/folders/zz/lwbnbx41153d7k9cwy_y3f4r0000gp/T/lAwsmUsersCreate@1445934279765/bundled.js JAWS: Lambda Deployer: Minified file written to /var/folders/zz/lwbnbx41153d7k9cwy_y3f4r0000gp/T/lAwsmUsersCreate@1445934279765/minified.js JAWS: Lambda Deployer: Compressed lambda written to /var/folders/zz/lwbnbx41153d7k9cwy_y3f4r0000gp/T/lAwsmUsersCreate@1445934279765/package.zip JAWS: Lambda Deployer: Uploading lAwsmUsersCreate to jaws.dev.apnortheast1.myapp-vkdqvcpw.com JAWS: Running CloudFormation lambda deploy... JAWS: Lambda Deployer: Done deploying lambdas in ap-northeast-1 JAWS: Lambda Deployer: Successfully deployed lambdas to the requested regions! JAWS: ------------------------------------------- JAWS: Dashboard: Deploying Endpoints... JAWS: ------------------------------------------- JAWS: Endpoint Deployer: Deploying endpoint(s) to region "ap-northeast-1"... JAWS: Endpoint Deployer: "dev - ap-northeast-1": found 3 endpoints to deploy JAWS: Endpoint Deployer: "dev - ap-northeast-1": created a new REST API on AWS API Gateway with ID: fmeeah15nk JAWS: Endpoint Deployer: "dev - ap-northeast-1": found 1 existing resources on API Gateway JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/authenticate": created resource: users JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/authenticate": created resource: authenticate JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/authenticate": created method: POST JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/authenticate": created integration with the type: AWS JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/authenticate": created new lambda access policy statement JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/authenticate": created method response JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/authenticate": created method response JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/authenticate": created method integration response JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/authenticate": created method integration response JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/create": created resource: create JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/create": created method: POST JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/create": created integration with the type: AWS JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/create": created new lambda access policy statement JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/create": created method response JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/create": created method response JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/create": created method integration response JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/create": created method integration response JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/list": created resource: list JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/list": created method: GET JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/list": created integration with the type: AWS JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/list": created new lambda access policy statement JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/list": created method response JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/list": created method response JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/list": created method integration response JAWS: Endpoint Deployer: "dev - ap-northeast-1 - users/list": created method integration response JAWS: Endpoint Deployer: Endpoints for stage "dev" successfully deployed to API Gateway in the region "ap-northeast-1". Access them @ https://fmeeah15nk.execute-api.ap-northeast-1.amazonaws.com/dev/ JAWS: ------------------------------------------- JAWS: Dashboard: Deployments Completed JAWS: -------------------------------------------
動作確認
Create
/users/create
にemailとpasswordをPOSTしてユーザを作成します。DynamoDBのjaws-usersテーブルを確認すると、レコードが1行作成されていることがわかります。
$ curl -X POST -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{ "email": "jacob@jaws.com", "password": "password" }' 'https://9ah96mtt80.execute-api.ap-northeast-1.amazonaws.com/dev/users/create' {}%
Authenticate
/users/authenticate
に先ほど登録したemailとpasswordをPOSTして作成したユーザで認証をします。認証が成功するとjwt(JSON Web Token)が返されます。
$ curl -X POST -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{ "email": "jacob@jaws.com", "password": "password" }' 'https://9ah96mtt80.execute-api.ap-northeast-1.amazonaws.com/dev/users/authenticate' | jq . {"status":201,"jwt":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiJ1XzBlZTM0ZjkwLTdjODktMTFlNS04MTcxLTZiMjAyMWEwNDIyMCIsImlhdCI6MTQ0NTkzNjQ0OCwiZXhwIjoxNDQ1OTM3MDQ4LCJpc3MiOiJpc3N1ZXIifQ.-6kceqqztCpjX4JPFeJUe5WZF-_RAqSjNntI9zQzDzM"}%
List
/users/list
にAuthorization: jwtを付与してGETすることで、認可され情報を取得することができます。
$ curl -H "Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiJ1XzBiN2U1YTAwLTdlZjctMTFlNS1iNmE0LTIzZGIwNWZjZTlkZSIsImlhdCI6MTQ0NjIwMzU2NSwiZXhwIjoxNDQ2MjA0MTY1LCJpc3MiOiJpc3N1ZXIifQ.nmY7fwrA2XTlmOI7o_0EXoiDFMMaFlmZlvq-gPpr3Lk" "https://9ah96mtt80.execute-api.ap-northeast-1.amazonaws.com/dev/users/list" | jq . (以下略)
まとめ
JAWSを使ったユーザ認証・認可のAPIを紹介しました。JAWSにはまだまだ少ないですがこのような機能を標準化したパッケージがいくつかあります。これらを雛形にしてアプリケーションを作ることで、開発の初速度をアップすることができますね。あと個人的な注目ポイントは環境変数が使えることです。AWS Lambda自体には環境変数はまだサポートされていませんが、JAWSがサポートしてくれています。アプリケーションを作るうえではコードに埋め込みたくない設定値などが必ず出てくるのですごく助かります。